package com.dog.basics.netty.agreement;
import cn.hutool.core.util.StrUtil;
import com.dog.basics.common.util.ByteUtil;
import com.dog.basics.netty.consts.Const;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;


/**
 * @program:  PROTOBUF . 解码
 * @description:
 * @author: Guo
 * @create: 2019-12-24 19:47
 **/
public class DogProtobufDecoder extends LengthFieldBasedFrameDecoder {

    /**
     * @param maxFrameLength      帧的最大长度
     * @param lengthFieldOffset   length字段偏移的地址
     * @param lengthFieldLength   length字段所占的字节长
     * @param lengthAdjustment    修改帧数据长度字段中定义的值，可以为负数 因为有时候我们习惯把头部记入长度,若为负数,则说明要推后多少个字段
     * @param initialBytesToStrip 解析时候跳过多少个长度
     * @param failFast            为true，当frame长度超过maxFrameLength时立即报TooLongFrameException异常，为false，读取完整个帧再报异
     */

    public DogProtobufDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip, boolean failFast) {

        super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip, failFast);

    }

    @Override
    protected Object decode(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {
        /**
         * 在这里调用父类的方法,实现指得到想要的部分,我在这里全部都要,也可以只要body部分
         */
        byteBuf = (ByteBuf) super.decode(ctx, byteBuf);
        /**
         * 判断字节流是否为空
         */
        if (byteBuf == null) {
            return null;
        }
        /**
         * 最短字节多少位 - 给予判断
         */
        if (byteBuf.readableBytes() < Const.acceptMinMsgLength) {
            throw new Exception("字节数不足");
        }
        /**
         * 获取共多少位字节 - 用于总共字节判断
         */
        int bytesLength = byteBuf.readableBytes();
        /**
         * 截取最后一个 - 一一解析其它信息
         */
        ByteBuf in = byteBuf.readBytes(bytesLength - 1);
        /**
         * 异或值计算
         */
        int temp = 0;
        for (int i = 0; i < in.readableBytes(); i++) {
            temp ^= in.getByte(i);
        }
        /**
         * 校验异或值
         */
        byte aByte = byteBuf.getByte(bytesLength - 1);
        if (aByte != temp) {
            throw new Exception("校验XOR异和值篡改风险给予拦截不要.");
        }
        /**
         * 获取帧头并且 - 转处理
         */
        byte[] head = new byte[]{in.readByte(), in.readByte(), in.readByte(), in.readByte()};
        /**
         * 判断帧头 - (俗称头部)
         */

        if (!StrUtil.equals(StrUtil.str(head, "UTF-8"), Const.headDefaultSrt)) {
            throw new Exception("帧头不符合");
        }
        /**
         * 判断帧长度是否符合
         */
        byte[] lengthBytes = new byte[4];
        in.readBytes(lengthBytes);
        int length = ByteUtil.byteArrayToInt(lengthBytes);
        if (bytesLength != length) {
            throw new Exception("帧长度不符合实际长度");
        }
        /**
         * 获取版地址
         */
        byte verAddress = in.readByte();

        //  转换为 Protobuf 剩余的 字节 以供 转换
        ByteBuf byteBuf1 = extractFrame(ctx, byteBuf, 9, in.readableBytes());
        return byteBuf1;
    }
}
